#ifndef KEYBOARD_HPP_
#define KEYBOARD_HPP_

#include <Mint/Types.h>
#include <Mint/Errors.h>
#include "Interfaces/ITextInput.h"

#if TRACE_DRIVERS_KEYBOARD
#define KEYBOARD_TRACE(x ...) TRACE("Keyboard: " x)
#else
#define KEYBOARD_TRACE(x ...)
#endif

enum
{
	KEYBOARD_MAX_EVENTS = 64,

	KEYBOARD_MODIFIER_PRESSED = 0x0001,
	KEYBOARD_MODIFIER_SHIFT = 0x0010,
	KEYBOARD_MODIFIER_CONTROL = 0x0020,
	KEYBOARD_MODIFIER_ALT = 0x0040,
	KEYBOARD_MODIFIER_SUPER = 0x0080,
	KEYBOARD_MODIFIER_MENU = 0x0100,
	KEYBOARD_MODIFIER_CAPS_LOCK = 0x0200,
	KEYBOARD_MODIFIER_SCROLL_LOCK = 0x0400,
	KEYBOARD_MODIFIER_NUM_LOCK = 0x0800,
};

typedef struct KeyboardEvent_s KeyboardEvent_t;

struct KeyboardEvent_s
{
	uint16	fKeyCode;
	uint16	fModifiers;
};

class CKeyboard : ITextInput
{
public:
	Result Initialize( uint16 * keymap );
	void SetKeymap( uint16 * keymap ) { fKeymap = keymap; }

	char Read( void );

	bool HasEvent( void ) { return fWritePos != fReadPos; }
	void ReadEvent( KeyboardEvent_t * event );
	void PeekEvent( KeyboardEvent_t * event );
	void WriteEvent( KeyboardEvent_t * event );

private:
	void _WaitUntilReady( void );
	void _SendCommand( uint8 command );
	void _SendCommand( uint8 command, uint8 value );
	void _HandleInterrupt( ITaskContext * context );
	static void __HandleInterrupt( ITaskContext * context );

private:
	uint32			fReadPos;
	uint32			fWritePos;
	KeyboardEvent_t	fEvents[KEYBOARD_MAX_EVENTS];
	uint16			fHeld;
	uint16			fModifiers;
	uint8			fLEDs;
	const uint16 *	fKeymap;
};

extern CKeyboard * Keyboard;

#endif /*KEYBOARD_HPP_*/
